/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const path = require('path');
const fs = require('fs');
const ts = require('typescript');
const ExcelJS = require('exceljs');
const applicationModules = [];

const typeCollection = true;
const isNotMerge = false;
function collectArkUiApis() {
  const apis = [];
  const arkUiApiDir = path.resolve(__dirname, '../sdk/build-tools/ets-loader/declarations');
  try {
    readFile(arkUiApiDir, apis);
  } catch (error) {
    return;
  }
  return apis;
}

function parseFiles(files) {
  files = files.concat(collectArkUiApis());
  const fileContentList = [];
  files.forEach(file => {
    let fileContent = fs.readFileSync(file, 'utf-8');
    fileContentList.push({
      fileName: path.basename(file).replace(/.d.ts$/g, '.ts'),
      fileContent: fileContent,
      fileRoot: file
    })
  });

  const api = [];
  const exportApi = [];
  const returnDeclarationArr = new Set([]);
  const hash = new Set([]);

  fileContentList.forEach(item => {
    const fileName = item.fileName.replace(/\.d.ts$/g, '.ts');
    let packageName = item.fileRoot.indexOf("build-tools\\ets-loader\\declarations") >= 0 ||
      item.fileRoot.indexOf("build-tools/ets-loader/declarations") >= 0 ?
      "ArkUI" : fileName.replace(/\@|.ts$/g, "");
    ts.transpileModule(item.fileContent, {
      compilerOptions: {
        "target": ts.ScriptTarget.ES2017
      },
      fileName: fileName,
      transformers: { before: [getReturnDeclarationArr(packageName, exportApi, returnDeclarationArr, fileName)] }
    })
  });

  fileContentList.forEach(item => {
    const fileName = item.fileName.replace(/\.d.ts$/g, '.ts');
    let packageName = item.fileRoot.indexOf("build-tools\\ets-loader\\declarations") >= 0 ||
      item.fileRoot.indexOf("build-tools/ets-loader/declarations") >= 0 ? "ArkUI" :
      fileName.replace(/\@|.ts$/g, "");
    ts.transpileModule(item.fileContent, {
      compilerOptions: {
        "target": ts.ScriptTarget.ES2017
      },
      fileName: fileName,
      transformers: { before: [processDeclarationSourceFile(packageName, api, exportApi, returnDeclarationArr, hash)] }
    })
  });
  return api;
}
exports.parseFiles = parseFiles;


function visitAllNode(node, returnDeclarationArr, packageName) {
  if ((ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node)) && node && node.type &&
    ts.isTypeReferenceNode(node.type)) {
    returnDeclarationArr.add(node.type.typeName.getText())
  }

  if (ts.isModuleDeclaration(node) && ts.isModuleBlock(node.body) && node.body && node.body.statements) {
    node.body.statements.forEach(statement => {
      if (statement.name) {
        applicationModules.push({
          packageName: packageName,
          className: node.name.escapedText,
          methodName: statement.name.escapedText
        })
      }
    })
  }
  node.getChildren().forEach(item => visitAllNode(item, returnDeclarationArr, packageName));
}

function getExportApi(node, packageName, exportApi) {
  node.statements.forEach(stat => {
    if (ts.isModuleDeclaration(stat)) {
      if (stat.getText().indexOf('namespace') > 0) {
        let apiInfo = {
          isSystemApi: '公开API',
          version: '',
          deprecated: '',
          permission: 'N/A',
          sysCap: 'N/A',
          model: ''
        }
        exportApi.push({
          packageName: packageName,
          className: stat.name.escapedText.toString(),
          methodName: '',
          apiInfo: getApiInfo(stat, apiInfo)
        })
      }
    }
  });
}

const getReturnDeclarationArr = (packageName, exportApi, returnDeclarationArr, fileName) => {
  return (context) => {
    return (node) => {
      visitAllNode(node, returnDeclarationArr, packageName);
      getExportApi(node, packageName, exportApi);
      return node;
    }
  }
}
exports.applicationModules = applicationModules;

function processDeclarationSourceFile(packageName, api, exportApi, returnDeclarationArr, hash) {
  return (context) => {
    return (node) => {
      const statements = node.statements;
      const currentClassFunSet = new Set([]);
      const currentTypeList = new Array();
      statements.forEach(stat => {
        if (ts.isTypeAliasDeclaration(stat)) {
          if (stat.type.types) {
            let typeObj = {
              name: stat.name.escapedText,
              value: []
            }
            stat.type.types.forEach(type => {
              if (type.literal && type.literal.text) {
                typeObj.value.push(type.literal.text);
              }
            });
            if (typeObj.value.length > 0) {
              currentTypeList.push(typeObj);
            }
          }
        }
      })

      statements.forEach(stat => {
        let apiInfo = {
          isSystemApi: '公开API',
          version: '',
          deprecated: '',
          permission: 'N/A',
          sysCap: 'N/A',
          model: ''
        }
        if (ts.isInterfaceDeclaration(stat)) {
          collectInterfaceDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
        } else if (ts.isModuleDeclaration(stat)) {
          collectModuleDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
        } else if (ts.isClassDeclaration(stat)) {
          collectClassDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
        } else if (ts.isEnumDeclaration(stat)) {
          collectEnumDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList);
        } else if (ts.isTypeAliasDeclaration(stat)) {

        } else {
          if (ts.isMethodDeclaration(stat) || ts.isMethodSignature(stat) || ts.isFunctionDeclaration(stat)) {
            var methodName = stat.name.escapedText ? stat.name.escapedText.toString() : stat.name.text.toString();
            let className = '';
            exportApi.forEach(item => {
              if (item.methodName == methodName && item.packageName == packageName) {
                className = item.className
                if (item.apiInfo) {
                  apiInfo = item.apiInfo;
                }
              }
            })
            addFunctionOnOffApi(packageName, className, methodName, getApiInfo(stat, apiInfo), 'Method', api,
              hash, currentClassFunSet, stat);
          }
        }
      })
      return node;
    }
  }
}

function collectInterfaceDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
  const className = stat.name.escapedText.toString();
  const interfaceChildren = stat.members;
  collectEachChildNode(interfaceChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash,
    getApiInfo(stat, apiInfo), currentTypeList)
}

function collectClassDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
  const className = stat.name.escapedText.toString();
  const classChildren = stat.members;
  collectEachChildNode(classChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash,
    getApiInfo(stat, apiInfo), currentTypeList)
}

function collectEnumDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
  const className = stat.name.escapedText.toString();
  const enumChildren = stat.members;
  collectEachChildNode(enumChildren, packageName, className, 'Enum', api, exportApi, returnDeclarationArr, hash,
    getApiInfo(stat, apiInfo), currentTypeList)
}

function collectModuleDeclaration(stat, packageName, api, exportApi, returnDeclarationArr, hash, apiInfo, currentTypeList) {
  const className = stat.name.escapedText ? stat.name.escapedText.toString() : stat.name.text.toString();
  const moduleChildren = stat.body.statements;
  collectEachChildNode(moduleChildren, packageName, className, 'Field', api, exportApi, returnDeclarationArr, hash,
    getApiInfo(stat, apiInfo), currentTypeList)
}

function collectEachChildNode(children, packageName, className, faterApiType, api, exportApi, returnDeclarationArr,
  hash, apiInfo, currentTypeList) {
  const currentClassFunSet = new Set([]);
  children.forEach(child => {
    if (ts.isTypeAliasDeclaration(child)) {
      if (child.type) {
        let typeObj = collectTypeApi(child, packageName, className, faterApiType, api, exportApi, returnDeclarationArr,
          hash, apiInfo);
        if (typeObj.value.length > 0) {
          currentTypeList.push(typeObj)
        }
      }
    }
  });

  children.forEach(child => {
    let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
    let apiType = new String(faterApiType);

    if (/export.*\{.*\}/g.test(child.getText())) {
      exportApi.push({
        packageName: packageName,
        className: className,
        methodName: child.getText().replace("export", '').replace('{', '').replace('}', '').replace(';', '').trim(),
        apiInfo: faterApiInfo
      })
      return
    }

    if (ts.isInterfaceDeclaration(child)) {
      collectInterfaceDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
    } else if (ts.isModuleDeclaration(child)) {
      collectModuleDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
    } else if (ts.isClassDeclaration(child)) {
      collectClassDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
    } else if (ts.isEnumDeclaration(child)) {
      collectEnumDeclaration(child, packageName, api, exportApi, returnDeclarationArr, hash, faterApiInfo);
    } else {
      if ((ts.isMethodDeclaration(child) || ts.isMethodSignature(child) || ts.isFunctionDeclaration(child)) &&
        (child.name.escapedText === 'on' || child.name.escapedText === 'off') && child.parameters && child.parameters.length > 0) {
        apiType = 'Method';
        collectSpecialApis(child, apiType, packageName, className, faterApiInfo, api, exportApi, currentTypeList,
          hash, apiInfo, currentClassFunSet);
      } else {
        collectMethodOrFieldApis(child, packageName, className, faterApiInfo, apiType, api,
          hash, currentClassFunSet, child, returnDeclarationArr);
      }
    }
  });
}

function collectMethodOrFieldApis(child, packageName, className, faterApiInfo, apiType, api,
  hash, currentClassFunSet, child, returnDeclarationArr) {
  let methodName = '';
  if (ts.isMethodDeclaration(child) || ts.isMethodSignature(child) || ts.isFunctionDeclaration(child) ||
    ts.isCallSignatureDeclaration(child) || ts.isConstructSignatureDeclaration(child) ||
    ts.isIndexSignatureDeclaration(child)) {
    if (child.name) {
      methodName = child.name.getText();
    } else {
      methodName = className;
    }
    apiType = 'Method'
  } else if (ts.isPropertyDeclaration(child) || ts.isPropertySignature(child)) {
    if (child.type && child.type.parameters) {
      methodName = child.name.escapedText;
      apiType = 'Method'
    } else {
      methodName = child.name.escapedText;
      apiType = 'Field';
    }
  } else {
    if (child.name) {
      methodName = child.name.getText();
    }
  }

  if (methodName !== '') {
    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
      hash, currentClassFunSet, child);
  } else {
    if (child.getText().indexOf('constructor') == 0) {
      methodName = 'constructor';
      apiType = 'Method';
    } else if (child.getText().indexOf("const") == 0) {
      const dataObj = collectFiledOrConstant(apiType, methodName, child, returnDeclarationArr);
      methodName = dataObj.name;
      apiType = dataObj.apiType;
    } else if (/\w+:\s*\w+/g.test(child.getText())) {
      apiType = 'Field';
      methodName = child.getText().split(":")[0].trim()
    }

    if (methodName != '') {
      addApi(packageName, className, methodName, child.getText(),
        getApiInfo(child, faterApiInfo), apiType, api, hash);
    }
  }
}

function collectFiledOrConstant(apiType, methodName, child, returnDeclarationArr) {
  if (child.getText().replace("const", "").indexOf(":") > 0) {
    if (returnDeclarationArr.has(child.getText().replace("const", "").split(":")[1].trim())) {
      apiType = 'Field';
    } else {
      apiType = 'Constant';
    }
    methodName = child.getText().replace('const', "").split(":")[0].trim();
  } else if (child.getText().replace("const", "").indexOf("=") > 0) {
    if (returnDeclarationArr.has(child.getText().replace("const", "").split("=")[1].trim())) {
      apiType = 'Field';
    } else {
      apiType = 'Constant';
    }
    methodName = child.getText().replace('const', "").split("=")[0].trim();
  }
  return { apiType, methodName };
}

function collectSpecialApis(child, apiType, packageName, className, faterApiInfo, api, exportApi, currentTypeList,
  hash, apiInfo, currentClassFunSet) {
  for (let i = 0; i < child.parameters.length; i++) {
    const param = child.parameters[i];
    if (param.name.escapedText === 'type' || param.name.escapedText === 'event' ||
      param.name.escapedText === 'eventType') {
      collectCommonTypesOfApi(packageName, className, faterApiInfo, apiType, api, hash, currentClassFunSet,
        child, currentTypeList, param);
      break;
    } else {
      let methodName = child.name.escapedText;
      addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
        hash, currentClassFunSet, child);
    }
  }
}

function collectCommonTypesOfApi(packageName, className, faterApiInfo, apiType, api, hash, currentClassFunSet,
  child, currentTypeList, param) {
  if (param.type && param.type.literal && param.type.literal.text) {
    const typeTextArr = param.getText().replace(/\s*/g, "").split(':');
    if (typeTextArr[0] === "type" || typeTextArr[0] === "event") {
      let methodName = child.name.escapedText + '_' + param.type.literal.text;
      addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
        hash, currentClassFunSet, child);
    }
  } else if (param.type && param.type.types && param.type.types.length > 0) {
    param.type.types.forEach(type => {
      if (type.literal && type.literal.text) {
        let methodName = child.name.escapedText + "_" + type.literal.text;
        addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
          hash, currentClassFunSet, child);
      }
    });
  } else if (param.type && param.type.typeName && param.type.typeName.escapedText) {
    collectInCurrentTypeListApi(packageName, className, faterApiInfo, apiType, api,
      hash, currentClassFunSet, child, currentTypeList, param);
  } else {
    let methodName = child.name.escapedText;
    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
      hash, currentClassFunSet, child);
  }
}

function collectInCurrentTypeListApi(packageName, className, faterApiInfo, apiType, api,
  hash, currentClassFunSet, child, currentTypeList, param) {
  if (currentTypeList && currentTypeList.length > 0) {
    currentTypeList.forEach(type => {
      if (type.name == param.type.typeName.escapedText) {
        type.value.forEach(typeString => {
          let methodName = child.name.escapedText + "_" + typeString;
          addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
            hash, currentClassFunSet, child);
        });
      }
    });
  } else if (param.type.typeName.escapedText === 'InnerEvent') {
    let methodName = child.name.escapedText + "_" + param.type.typeName.escapedText;
    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
      hash, currentClassFunSet, child);
  } else {
    let methodName = child.name.escapedText;
    addFunctionOnOffApi(packageName, className, methodName, faterApiInfo, apiType, api,
      hash, currentClassFunSet, child);
  }
}

function collectTypeApi(child, packageName, className, faterApiType, api, exportApi, returnDeclarationArr,
  hash, apiInfo) {
  let typeObj = {
    name: child.name.escapedText,
    value: []
  }

  if (child.type.types) {
    child.type.types.forEach(type => {
      if (type.literal && type.literal.text) {
        typeObj.value.push(type.literal.text);
        if (typeCollection) {
          let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
          addApi(packageName, child.name.escapedText, type.literal.text, child.getText(),
            getApiInfo(child, faterApiInfo), 'Type', api, hash);
        }
      } else {
        if (type.getText() != '') {
          typeObj.value.push(type.getText());
          if (typeCollection) {
            let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
            addApi(packageName, child.name.escapedText, type.getText(), child.getText(),
              getApiInfo(child, faterApiInfo), 'Type', api, hash);
          }
        }
      }
    });
  } else if (child.type.members) {
    child.type.members.forEach(member => {
      member.type.types.forEach(type => {
        collectMembersApi(type, packageName, child, api, hash, typeObj, apiInfo, className);
      });
    })
  }
  return typeObj;
}

function collectMembersApi(type, packageName, child, api, hash, typeObj, apiInfo, className) {
  if (type.literal && type.literal.text) {
    typeObj.value.push(type.literal.text);
    if (typeCollection) {
      let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
      addApi(packageName, child.name.escapedText, type.literal.text, child.getText(),
        getApiInfo(child, faterApiInfo), 'Type', api, hash);
    }
  } else {
    if (type.getText() != '') {
      typeObj.value.push(type.getText());
      if (typeCollection) {
        let faterApiInfo = JSON.parse(JSON.stringify(apiInfo));
        addApi(packageName, className, child.name.escapedText, child.getText(),
          getApiInfo(child, faterApiInfo), 'Type', api, hash);
      }
    }
  }
}

function addFunctionOnOffApi(packageName, className, methodName, apiInfo, apiType, api,
  hash, currentClassFunSet, childNode) {
  if (currentClassFunSet.has(methodName) && !isNotMerge) {
    for (let i = 0; i < api.length; i++) {
      const curApi = api[i];
      if (curApi.packageName === packageName && curApi.className === className &&
        curApi.methodName === methodName) {
        if (curApi.methodText.indexOf(`${childNode.getText().replace('declare', '').trim()}`) < 0) {
          curApi.methodText += `<br>${childNode.getText().replace('declare', '').trim()}`;
          break;
        }
      }
    }
  } else {
    if (!currentClassFunSet.has(methodName)) {
      currentClassFunSet.add(methodName);
      addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(),
        getApiInfo(childNode, apiInfo), apiType, api, hash);
    } else {
      if (childNode.getFullText().indexOf('\/**') >= 0) {
        addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(),
          getApiInfo(childNode, apiInfo), apiType, api, hash);
      } else {
        let firstApiInfo = {};
        for (let i = 0; i < api.length; i++) {
          const curApi = api[i];
          if (curApi.packageName === packageName && curApi.className === className &&
            curApi.methodName === methodName) {
            firstApiInfo.isSystemApi = curApi.isSystemApi;
            firstApiInfo.version = curApi.version;
            firstApiInfo.sysCap = curApi.sysCap;
            firstApiInfo.permission = curApi.permission;
            firstApiInfo.model = curApi.model;
          }

        }
        addApi(packageName, className, methodName, childNode.getText().replace('declare', '').trim(),
          firstApiInfo, apiType, api, hash);
      }
    }
  }
}

function getApiInfo(node, apiInfo) {
  const notesStr = node.getFullText().replace(node.getText(), "");

  if (notesStr !== "") {
    if (/\@[S|s][Y|y][S|s][T|t][E|e][M|m][A|a][P|p][I|i]/g.test(notesStr)) {
      apiInfo.isSystemApi = '系统API'
    }
    if (/\@[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g.test(notesStr)) {
      notesStr.replace(/\@[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g, (versionInfo) => {
        apiInfo.version = versionInfo.replace(/\@[S|s][I|i][N|n][C|c][E|e]/g, '').trim();
      })
    }
    if (/\@[D|d][E|e][P|p][R|r][E|e][C|c][A|a][T|t][E|e][D|d].*[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g.test(notesStr)) {
      notesStr.replace(/\@[D|d][E|e][P|p][R|r][E|e][C|c][A|a][T|t][E|e][D|d].*[S|s][I|i][N|n][C|c][E|e]\s*(\d+)/g,
        versionInfo => {
          apiInfo.deprecated = versionInfo.replace(
            /\@[D|d][E|e][P|p][R|r][E|e][C|c][A|a][T|t][E|e][D|d].*[S|s][I|i][N|n][C|c][E|e]\s*/g, '').trim();
        })
    }
    if (/\@[F|f][A|a][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g.test(notesStr)) {
      notesStr.replace(/\@[F|f][A|a][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g, modelInfo => {
        apiInfo.model = modelInfo;
      })
    } else if (/\@[S|s][T|t][A|a][G|g][E|e][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g.test(notesStr)) {
      notesStr.replace(/\@[S|s][T|t][A|a][G|g][E|e][M|m][O|o][D|d][E|e][L|l][O|o][N|n][L|l][Y|y]/g, modelInfo => {
        apiInfo.model = modelInfo;
      })
    }
    if (/\@[S|s][Y|y][S|s][C|c][A|a][P|p]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g.test(notesStr)) {
      notesStr.replace(/\@[S|s][Y|y][S|s][C|c][A|a][P|p]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g, sysCapInfo => {
        apiInfo.sysCap = sysCapInfo.replace(/\@[S|s][Y|y][S|s][C|c][A|a][P|p]/g, '').trim();
      })
    }
    if (/\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g.test(notesStr)) {
      notesStr.replace(/\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]\s*((\w|\.|\/|\{|\@|\}|\s)+)/g,
        permissionInfo => {
          apiInfo.permission = permissionInfo.
            replace(/\@[P|p][E|e][R|r][M|m][I|i][S|s][S|s][I|i][O|o][N|n]/g, '').trim();
        })
    }
  }
  return apiInfo;
}

function addApi(packageName, className, methodName, methodText, apiInfo, apiType, api, hash) {
  let recard = isNotMerge ? `${packageName}.${className}/${methodName}/${methodText}` :
    `${packageName}.${className}/${methodName}`;
  
  if (!hash.has(recard)) {
    hash.add(recard);
    api.push({
      packageName: packageName,
      className: className,
      methodName: methodName,
      methodText: methodText.replace(/export\s/g, ""),
      isSystemApi: apiInfo.isSystemApi,
      version: apiInfo.version,
      deprecated: apiInfo.deprecated,
      apiType: apiType,
      sysCap: apiInfo.sysCap,
      permission: apiInfo.permission,
      model: apiInfo.model,
      applicationFile: '',
      pos: '',
      functionType: '',
      optionalArg: 0,
      arguments: 0
    })
  }
}

async function getExcelBuffer(api) {
  const workbook = new ExcelJS.Workbook();
  const sheet = workbook.addWorksheet('Js Api', { views: [{ xSplit: 1 }] });
  sheet.getRow(1).values = ['模块名', '类名', '方法名', '函数', '文件位置', '类型', 'SysCap',
    '权限', '支持起始版本', '访问级别']
  for (let i = 1; i <= api.length; i++) {
    const apiData = api[i - 1];
    sheet.getRow(i + 1).values = [apiData.packageName, apiData.className, apiData.methodName,
      apiData.methodText, apiData.pos, apiData.apiType, apiData.sysCap, apiData.permission,
      apiData.version, apiData.isSystemApi]
  }
  const buffer = await workbook.xlsx.writeBuffer();
  return buffer;
}

exports.getExcelBuffer = getExcelBuffer;

function readFile(dir, utFiles) {
  try {
    const files = fs.readdirSync(dir);
    files.forEach((element) => {
      const filePath = path.join(dir, element);
      const status = fs.statSync(filePath);
      if (status.isDirectory()) {
        readFile(filePath, utFiles);
      } else {
        if (/\.d\.ts/.test(filePath)) {
          utFiles.push(filePath)
        }
      }
    })
  } catch (e) {
    console.error('ETS ERROR: ' + e);
  }
}

exports.readFile = readFile;

async function excel(api) {
  let buffer = await getExcelBuffer(api)
  fs.writeFile('../Js_Api.xlsx', buffer, function (err) {
    if (err) {
      console.error('WEITE FAILED: ', err);
      return;
    } else {
      console.log('WRITE SUCCEED!');
    }
  });
}

exports.excel = excel;